package com.xiaohe.gulimall.search.thread;

import java.util.concurrent.*;

public class ThreadTest {

    //线程池
    public static ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        System.out.println("main....start..");
//        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程为" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果为" + i);
//        }, threadPool);
//        System.out.println("main....end");
        System.out.println("main....start..");
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程为" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果为" + i);
//            return i;
//        }, threadPool).whenComplete((res,exception)->{
//            //虽然能得到异常信息，但不能进行异常默认信息可以
//            System.out.println("异步任务成功完成了....结果是"+res+";异常是"+exception);
//        }).exceptionally(throwable -> {
//            //能够改变出现异常的返回结果
//            return 10;
//        });
//        Integer result = future.get();
//        System.out.println(result);
        /**
         * handle方法完成后的处理
         */
//        CompletableFuture<Integer> handle = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程为" + Thread.currentThread().getId());
//            int i = 10 / 0;
//            System.out.println("运行结果为" + i);
//            return i;
//        }, threadPool).handle((res, exception) -> {
//            if (res != null) {
//                return res * 2;
//            }
//            if (exception != null) {
//                return 0;
//            }
//            return 0;
//        });
//        Integer integer = handle.get();
//        System.out.println(integer);
        /**
         * 线程串行化，
         * thenRun 不能获取上一步的结果，无返回值
         *  threadPool).thenRunAsync(()->{
         *             System.out.println("任务2启动了");
         *         },threadPool);
         * thenAcceptAsync
         *   .thenAcceptAsync(res->{
         *             System.out.println("任务2执行了"+res);
         *         },threadPool);
         *
         */
/*        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程为" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果为" + i);
            return i;
        }, threadPool).thenApplyAsync(res -> {
            System.out.println("任务二启动了");
            return "Hello" + res;
        });
        String s = future.get();//阻塞方法
        System.out.println(s);
        System.out.println("main....end");*/
        /**
         * 两个都完成
         */
//        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1线程：" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("任务1结束" + i);
//            return i;
//        }, threadPool);
//
//        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1线程：" + Thread.currentThread().getId());
//            try {
//                Thread.sleep(3000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println("任务2结束");
//            return "Hello";
//        }, threadPool);

//        future1.runAfterBothAsync(future2,()->{
//            System.out.println("任务三开始");
//        },threadPool);
//        future1.thenAcceptBothAsync(future2, (f1, f2) -> {
//            System.out.println("任务三开始"+f1+"---->"+f2);
//        }, threadPool);

//        CompletableFuture<String> future = future1.thenCombineAsync(future2, (f1, f2) -> {
//            return f1 + ":" + f2 + "->" + "哈哈";
//        }, threadPool);
//        System.out.println(future.get());

        /**
         * 两个任务，只要有一个完成，我们就执行任务3
         */
//        future1.runAfterEitherAsync(future2,()->{
//            System.out.println("任务三开始");
//        },threadPool);
//        future1.acceptEitherAsync(future2, (res) -> {
//            System.out.println("任务三开始"+res);//没有返回值
//        }, threadPool);
//         future1.applyToEitherAsync(future2,(res)->{
//             System.out.println(res.toString()+"哈哈");
//             return res;
//         },threadPool);

        CompletableFuture<String> futureImage = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询图片信息");
            return "hello.jpg";
        }, threadPool);

        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("查询属性信息");
            } catch (InterruptedException e) {
            }
            return "黑色256G";
        }, threadPool);

        CompletableFuture<String> futureDESC = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品介绍");
            return "华为";
        }, threadPool);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImage, futureAttr, futureDESC);
        allOf.get();

        System.out.println("main....end");

    }


    //测试线程
    public void thread(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main.....start");
        /**
         * 1、继承Thread类
         * 2、实现Runnable接口
         * 3、实现callable接口+ futureTask
         * 4、线程池
         */
       /*
        1、继承Thread类
        Thread01 thread01 = new Thread01();
        thread01.start();
        System.out.println("main....end");
        */
       /*
        2、实现Runnable接口
        Runnable01 runnable01 = new Runnable01();
        new Thread(runnable01).start();
        System.out.println("main....end");
        */
       /*
        3、实现callable接口+ futureTask
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        //等待整个线程结束，获取请求结果  阻塞等待
        Integer integer = futureTask.get();
        System.out.println("main....end"+integer);
        */
        /**
         * 4、线程池
         *   给线程池直接提交任务
         *    threadPool.execute(new Runnable01());
         *    4.1、线程的创建
         *     4.1.1、使用Executors工具类
         *     4.1.2、使用        new ThreadPoolExecutor()
         *
         * 区别：
         * 1、2不能得到返回值，3可以获取返回值
         * 1、2、3都不能控制资源
         * 4可以控制资源
         */
        //我们以后再业务代码里面，以上三种启动线程的方式都不用，应该将多线程异步任务都交给线程池执行
        //当前系统中池只有一两个，每个异步任务，提交给线程池让他自己去执行就行
        /**
         * int corePoolSize,核心线程数【一直存在】，线程池创建好以后就准备就绪的线程数量，就等待来接收异步任务去执行
         *int maximumPoolSize,最大线程数量，控制资源并发
         *long keepAliveTime,存活时间，当前正在运行的线程数量大于核心数量，释放空闲的线程，只要线程空闲大于指定的keepAliveTime
         *TimeUnit unit,时间单位
         *BlockingQueue<Runnable> workQueue,阻塞队列，如果任务很多，就会将目前多的任务放在队列里面，只要有线程空闲，就会去队列里面取出新的任务继续执行
         *ThreadFactory threadFactory,线程的创建工厂
         *RejectedExecutionHandler handler 如果队列满了怎么办？按照我们指定的拒绝策略拒绝执行任务
         */
        /**
         * 工作顺序
         * 1、线程池创建，准备好 core 数量的核心线程，准备接受任务
         * 2、新的任务进来，用 core 准备好的空闲线程执行。
         *   (1) 、core 满了，就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队
         * 列获取任务执行
         *   (2) 、阻塞队列满了，就直接开新线程执行，最大只能开到 max 指定的数量
         *   (3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自
         * 动销毁。最终保持到 core 大小
         *   (4) 、如果线程数开到了 max 的数量，还有新任务进来，就会使用 reject 指定的拒绝策
         * new LinkedBlockingDeque<>() 默认是Integer的最大值，内存不够
         *
         * 一个线程池 core 7 max 20 queue:50 100个并发进来怎么分配
         * 7个会立即执行，50个进入队列，再开13个进去执行，剩下的30个就使用拒绝策略来执行
         * 如果不想抛弃还要执行CallerRunsPolicy
         */
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5,
                200,
                5,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        //Executors.newCachedThreadPool()  缓存池  core=0，所有都要进行回收
        //Executors.newFixedThreadPool() 固定大小的线性池。core =max 都不能进行回收
        //Executors.newScheduledThreadPool() 定时任务的线性池
        //Executors.newSingleThreadExecutor() 单线程的线程池，后台从队列里面依次进行
    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程为" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果为" + i);
        }
    }

    public static class Runnable01 implements Runnable {

        @Override
        public void run() {
            System.out.println("当前线程为" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果为" + i);
        }
    }

    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程为" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果为" + i);
            return i;
        }
    }
}
